from Tkinter import *
import time
import datetime
import Panel
import pickle

class Task(object):
	
	def __init__(self, name, hoursTotal, hoursCompleted, dueDate, description, color, outlineColor, flagOutlineColor):
		self.name = name
		self.hoursTotal = hoursTotal
		self.hoursCompleted = hoursCompleted
		self.dueDate = dueDate
		self.description = description
		self.color = color
		self.outlineColor = outlineColor
		self.flagOutlineColor = flagOutlineColor
		self.daysRemaining = self.calculateDaysRemaining()
		self.totalSubtasks = 0
		self.completedSubtasks = 0
		
	def calculateDaysRemaining(self):
		return (self.dueDate - datetime.datetime.today()).days 
	
	def saveTask(self):
		s = pickle.dumps(self)

	
	def __str__(self):
		return self.name + " " + self.description
	
class RegTask(Task):
	
	def __init__(self, name="", hoursTotal=1, hoursCompleted=0, dueDate=datetime.datetime.today(), description="", x=0, y=0, isFlagged = False, scalingFactor=5, scalingFactor2 = 10, panel = "" ):
		Task.__init__(self, name, hoursTotal, hoursCompleted, dueDate, description, "navy blue", "dark blue", "sky blue")
		self.panel = panel if panel != "" else Panel.Panel()
		self.tk = self.panel.tk
		self.canvas = self.panel.canvas
		self.isFlagged = isFlagged
		self.isEnlarged = False
		self.radius = int(self.calculateScaledHoursRemaining() * scalingFactor2)
		self.x = x
		self.y = y
		self.coordinates = self.swapCoords(x,y,self.radius)
		self.canShrink = True
		self.fontScalingFactor = 5
		self.fontsize = self.radius  / self.fontScalingFactor
		self.originalScalingFactor = scalingFactor
		self.scalingFactor = self.calculateScalingFactor(scalingFactor)
		self.scalingFactor2 = scalingFactor2
		self.enlargedRadius = self.radius * self.scalingFactor
		self.enlargedFont = self.fontsize * self.scalingFactor
		self.taskType = "Task"
		self.start(x, y)

	def setTaskText(self, isEnlarged):
		secondLine = ""
		if len(' '.join(self.description.strip().split())) > 17:
			secondLine = "\n" + ' '.join(self.description[17:33].strip().split())
		textHere = self.name[0:15].strip() + "\n" + ' '.join(self.description[0:17].strip().split()) + secondLine + "\n" + str(self.hoursCompleted) + "/" +  str(self.hoursTotal) + " hours done"
		if isEnlarged:
			fontSize = self.enlargedFont
		else:
			fontSize = self.fontsize
		self.canvas.itemconfig(self.circleText, text = textHere)
		
	def calculateScaledHoursRemaining(self):
		return (self.hoursTotal - self.hoursCompleted)**.6

	def calculateScalingFactor(self, scalingFactor):
		s = int(scalingFactor / (self.calculateScaledHoursRemaining()))	
		if s==1 or s==0:
			return 2
		else:
			return s

	def start(self, x, y):
		outlinePad = 5
		self.circleOutline = self.canvas.create_oval(self.coordinates[0] + outlinePad, self.coordinates[1] + outlinePad, self.coordinates[2] - outlinePad, self.coordinates[3] - outlinePad, fill=self.flagOutlineColor)
		self.setOutlineColor()
		self.circle = self.canvas.create_oval(self.coordinates[0], self.coordinates[1], self.coordinates[2], self.coordinates[3], fill="dark blue", outline="dark blue")
		self.circleText = self.canvas.create_text(self.x,self.y, text="", fill="white", font=("purisa", self.fontsize, "bold"), state="disabled", justify="center")
		self.setTaskText(False)
		self.direction = 1
		self.canvas.tag_bind(self.circle, "<Enter>", self.enlargeCircle)
		self.canvas.tag_bind(self.circle, "<Leave>", self.shrinkCircle)
		self.canvas.tag_bind(self.circle, "<1>", self.showPopup)
		self.canvas.pack()
	
	def swapCoords(self, x, y, radius):
		x0 = x + radius * 7 / 5
		y0 = y + radius * 7 / 5
		x1 = x - radius * 7 / 5
		y1 = y - radius * 7 / 5
		return (x0, y0, x1, y1)


	def enlargeCircle(self, event):
		self.scalingFactor = self.calculateScalingFactor(self.originalScalingFactor)	
		if self.canShrink and not self.isEnlarged:
			self.raiseEvent()
			radius = self.radius
			for i in range(self.radius, self.radius*self.scalingFactor + 1, int(self.radius/20) + 1):
				self.setRadius(i, True)
				time.sleep(.05 / self.radius**2)
				self.tk.update()
			self.enlargedRadius = int(radius * self.scalingFactor)
			self.isEnlarged = True
		elif self.isEnlarged:
			self.setRadius(self.radius*self.scalingFactor, True)
		self.canShrink = True
		self.tk.update()

	def raiseEvent(self):
		self.canvas.tag_raise(self.circleOutline)
		self.canvas.tag_raise(self.circle)
		self.canvas.tag_raise(self.circleText)
	
	def shrinkCircle(self, event):
		if self.isNotClick(event) and self.canShrink:
			for i in reversed(range(self.radius, self.enlargedRadius, int(self.radius/20) + 1)):
				self.setRadius(i, False)
				time.sleep(.05 / self.radius**2)
				self.tk.update()
			self.isEnlarged = False
		else:
			self.canShrink = False

	def isNotClick(self, event):
		x1,y1 = event.x, event.y
		x2,y2 = self.x, self.y 	
		return ((x2-x1)**2 + (y2-y1)**2)**.5 > self.radius * self.scalingFactor

	def showPopup(self, event):
		self.editPopup = Tk()
		self.editPopup.title('hellzyeah')
		
		name = Label(self.editPopup, text = "Name ")
		self.nameEntry = Entry(self.editPopup, width=25)
		self.nameEntry.insert(0, self.name)
		
		description = Label(self.editPopup, text = "Description")
		self.descriptionEntry = Text(self.editPopup, width = 28, height = 3)		
		self.descriptionEntry.insert(END, self.description)
		
		hoursCompleted = Label(self.editPopup, text = "Hours Completed")
		self.hoursCompletedEntry = Entry(self.editPopup, width= 3)
		self.hoursCompletedEntry.insert(0, self.hoursCompleted)
		
		hoursTotal = Label(self.editPopup, text = "Hours Total")
		self.hoursTotalEntry = Entry(self.editPopup, width= 3)
		self.hoursTotalEntry.insert(0, self.hoursTotal)
		
		dueDate = Label(self.editPopup, text = "Due (MM/DD/YYYY)")
		self.dueDateEntry = Entry(self.editPopup, width = 10)
		self.dueDateEntry.insert(0, str(self.dueDate.month) + "/" + str(self.dueDate.day) + "/" + str(self.dueDate.year))
		
		updateButton = Button(self.editPopup, text = "Update Task", command = self.updateButtonClick)
		deleteButton = Button(self.editPopup, text = "Delete Task", command=self.deleteButtonClick)
		completeButton = Button(self.editPopup, text = "Completed!", width=10, height=2, command=self.completeButtonClick)
		
		checkButton = Checkbutton(self.editPopup, text = " Important Task? ", command=self.reverseOutline, variable = self.isFlagged)

		if self.isFlagged:
			checkButton.select()
		else:
			checkButton.deselect()
		
		self.editPopup.bind("<KeyPress-Return>", self.helpUpdateButton)
		
		name.grid(row=0, column=0, pady=3)
		self.nameEntry.grid(row=0, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		description.grid(row=1, column=0, pady=3)
		self.descriptionEntry.grid(row=1, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		hoursCompleted.grid(row=2, column=0, pady=3)
		self.hoursCompletedEntry.grid(row=2, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		hoursTotal.grid(row=3, column=0, pady=3)
		self.hoursTotalEntry.grid(row=3, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		dueDate.grid(row=4, column=0, pady=3)
		self.dueDateEntry.grid(row=4, column=1, pady=3, padx = 5, sticky = W, columnspan=2)
		
		updateButton.grid(row=6, column = 0, pady=15, columnspan = 2)
		deleteButton.grid(row=6, column = 1, padx = 50, sticky = W, columnspan=2)
		completeButton.grid(row=2, column = 2, rowspan = 2, sticky = W)
		checkButton.grid(row=4, column=2, sticky=E, pady=5)
		
	def helpUpdateButton(self, event):
		self.updateButtonClick()
	
	def reverseOutline(self):
		self.isFlagged = not self.isFlagged
		self.canvas.itemconfig(self.circleOutline, fill=self.flagOutlineColor)
		self.setOutlineColor()

		
	def setOutlineColor(self):
		if self.isFlagged:
			self.canvas.itemconfig(self.circleOutline, fill=self.flagOutlineColor)
		else:
			self.canvas.itemconfig(self.circleOutline, fill=self.outlineColor)

	def validation(self):
		name = self.nameEntry.get()
		description = self.descriptionEntry.get(1.0, END)
		hoursCompleted = self.hoursCompletedEntry.get()
		hoursTotal = self.hoursTotalEntry.get()
		self.dueDate = self.parseDateTime(self.dueDateEntry.get())

		try:
			int(hoursCompleted)
		except:
			hoursCompleted = "0"
		try:
			int(hoursTotal)
		except:
			hoursTotal = "1"

		self.name = name if len(name) > 0 else ""
		self.description = description if len(description) > 0 else ""
		self.hoursCompleted = int(hoursCompleted if (len(hoursCompleted) > 0) else 0 )
		self.hoursTotal = int(hoursTotal if (len(hoursTotal) > 0) else 1)
		

	def updateButtonClick(self):
		self.validation()
		if int(self.calculateScaledHoursRemaining())==0:
			self.deleteButtonClick()
		self.setRadius(int(self.calculateScaledHoursRemaining() * self.scalingFactor2), False)
		self.scalingFactor = self.calculateScalingFactor(self.scalingFactor)
		self.setTaskText(True)
		self.panel.moveAllTasks()
		self.editPopup.destroy()
		
	
	def setRadius(self, newRadius, isEnlarged):
		coords = self.swapCoords(self.x, self.y, newRadius)
		if not isEnlarged:
			self.radius = newRadius
		self.fontsize = newRadius / self.fontScalingFactor
		self.canvas.coords(self.circle, coords[0], coords[1], coords[2], coords[3])
		self.canvas.coords(self.circleOutline, coords[0] + 5, coords[1] + 5, coords[2] - 5, coords[3] - 5)
		self.canvas.itemconfig(self.circleText, font = ("purisa", self.fontsize, "bold"))
	
	def parseDateTime(self, dateString):
		sections = dateString.split("/")
		try:
			return datetime.datetime(int(sections[2]), int(sections[0]), int(sections[1]))
		except:
			return self.dueDate
	
	def deleteButtonClick(self):
		self.deleteTask()
		self.editPopup.destroy()
	
	def deleteTask(self):
		if isinstance(self, ProjectSubTask):
			self.panel.updateOwningProject(self.name, False)
		self.canvas.delete(self.circle)
		self.canvas.delete(self.circleText)
		self.canvas.delete(self.circleOutline)
		self.panel.deleteTask(self)
	
	def completeButtonClick(self):
		self.deleteTask()
		self.editPopup.destroy()
	
	def moveCircle(self, x, y):
		coord = self.swapCoords(x, y, self.radius)
		self.canvas.coords(self.circle, coord[0], coord[1], coord[2], coord[3])
		self.canvas.coords(self.circleOutline, coord[0] + 5, coord[1] + 5, coord[2] - 5, coord[3] - 5)
		self.canvas.coords(self.circleText, x, y)	
		self.x = x
		self.y = y	

	def blank(self, event):
		pass
		
class ProjectTask(RegTask):
	
	def __init__(self, name="", hoursTotal=1, hoursCompleted=0, dueDate=datetime.datetime.today(), description="", x=0, y=0,  isFlagged = False, scalingFactor=5, scalingFactor2 = 10, panel=""):
		RegTask.__init__(self, name, hoursTotal, hoursCompleted, dueDate, description, x, y, isFlagged, scalingFactor, scalingFactor2, panel )
		self.flagOutlineColor = "light green"
		self.outlineColor = "dark green"
		self.setOutlineColor()
		self.taskType = "Project"
		
	
	def start(self, x, y):
		outlinePad = 5
		coords = self.swapCoords(self.x, self.y, self.radius)
		self.circleOutline = self.canvas.create_rectangle(self.coordinates[0] + outlinePad, self.coordinates[1] + outlinePad, self.coordinates[2] - outlinePad, self.coordinates[3] - outlinePad, fill=self.flagOutlineColor)
		self.setOutlineColor()
		self.circle = self.canvas.create_rectangle(self.coordinates[0], self.coordinates[1], self.coordinates[2], self.coordinates[3], fill="dark green", outline="dark green")
		self.circleText = self.canvas.create_text(self.x,self.y, text="", fill="white", font=("purisa", self.fontsize, "bold"), state="disabled", justify="center")
		self.setTaskText(False)
		self.direction = 1
		self.canvas.tag_bind(self.circle, "<Enter>", self.enlargeCircle)
		self.canvas.tag_bind(self.circle, "<Leave>", self.shrinkCircle)
		self.canvas.tag_bind(self.circle, "<1>", self.showPopup)
		self.canvas.pack()		
	
	def calculateScaledHoursRemaining(self):
		return (self.hoursTotal - self.hoursCompleted)**.4
		
	def setTaskText(self, isEnlarged):
		secondLine = ""
		if len(' '.join(self.description.strip().split())) > 17:
			secondLine = "\n" + ' '.join(self.description[17:33].strip().split())
		textHere = self.name[0:15].strip() + "\n" + ' '.join(self.description[0:17].strip().split()) + secondLine + "\n" + str(self.hoursCompleted) + "/" +  str(self.hoursTotal) + " hours done" + "\n" + str(self.completedSubtasks) + "/" + str(self.totalSubtasks) + " subtasks done"
		if isEnlarged:
			fontSize = self.enlargedFont
		else:
			fontSize = self.fontsize
		self.canvas.itemconfig(self.circleText, text = textHere)

	def validation(self):
		previousName = self.name
		name = self.nameEntry.get()
		description = self.descriptionEntry.get(1.0, END)
		hoursCompleted = self.hoursCompletedEntry.get()
		hoursTotal = self.hoursTotalEntry.get()
		self.dueDate = self.parseDateTime(self.dueDateEntry.get())

		try:
			int(hoursCompleted)
		except:
			hoursCompleted = "0"
		try:
			int(hoursTotal)
		except:
			hoursTotal = "1"

		self.name = name if len(name) > 0 else ""
		self.description = description if len(description) > 0 else ""
		self.hoursCompleted = int(hoursCompleted if (len(hoursCompleted) > 0) else 0 )
		self.hoursTotal = int(hoursTotal if (len(hoursTotal) > 0) else 1)
		if isinstance(self, ProjectTask):
			self.panel.projectDict[self] = self.name
			self.panel.updateSubTaskNames(self, previousName)
	
	def changeTotalTasks(self, incrementOrDecrement):
		if incrementOrDecrement:
			self.totalSubtasks+=1
		else:
			self.totalSubtasks-=1
		self.setTaskText(False)
		
		

class ProjectSubTask(RegTask):
	
	def __init__(self, name="", hoursTotal=1, hoursCompleted=0, dueDate=datetime.datetime.today(), description="", x=0, y=0, isFlagged = False, scalingFactor=5, scalingFactor2 = 10, panel=""):
		RegTask.__init__(self, name, hoursTotal, hoursCompleted, dueDate, description, x, y, isFlagged, scalingFactor, scalingFactor2, panel )
		self.flagOutlineColor = "yellow"
		self.outlineColor = "dark orange"
		self.setOutlineColor()
		self.taskType = "Subtask"
		
	
	def start(self, x, y):
		outlinePad = 5
		coords = self.swapCoords(self.x, self.y, self.radius)
		self.circleOutline = self.canvas.create_arc(self.coordinates[0] + outlinePad, self.coordinates[1] + outlinePad, self.coordinates[2] - outlinePad, self.coordinates[3] - outlinePad, fill=self.flagOutlineColor, extent=270)
		self.setOutlineColor()
		self.circle = self.canvas.create_arc(self.coordinates[0], self.coordinates[1], self.coordinates[2], self.coordinates[3], fill="dark orange", outline="dark orange", extent=270)
		self.circleText = self.canvas.create_text(self.x,self.y, text="", fill="white", font=("purisa", self.fontsize, "bold"), state="disabled", justify="center")
		self.setTaskText(False)
		self.direction = 1
		self.canvas.tag_bind(self.circle, "<Enter>", self.enlargeCircle)
		self.canvas.tag_bind(self.circle, "<Leave>", self.shrinkCircle)
		self.canvas.tag_bind(self.circle, "<1>", self.showPopup)
		self.canvas.pack()
	
	def showPopup(self, event):
		self.editPopup = Tk()
		self.editPopup.title('hellzyeah')
		
		name = Label(self.editPopup, text = "Owning Project ")
		self.nameEntry = Label(self.editPopup, width=25, text=self.name)
		
		description = Label(self.editPopup, text = "Description")
		self.descriptionEntry = Text(self.editPopup, width = 28, height = 3)		
		self.descriptionEntry.insert(END, self.description)
		
		hoursCompleted = Label(self.editPopup, text = "Hours Completed")
		self.hoursCompletedEntry = Entry(self.editPopup, width= 3)
		self.hoursCompletedEntry.insert(0, self.hoursCompleted)
		
		hoursTotal = Label(self.editPopup, text = "Hours Total")
		self.hoursTotalEntry = Entry(self.editPopup, width= 3)
		self.hoursTotalEntry.insert(0, self.hoursTotal)
		
		dueDate = Label(self.editPopup, text = "Due (MM/DD/YYYY)")
		self.dueDateEntry = Entry(self.editPopup, width = 10)
		self.dueDateEntry.insert(0, str(self.dueDate.month) + "/" + str(self.dueDate.day) + "/" + str(self.dueDate.year))
		
		updateButton = Button(self.editPopup, text = "Update Task", command = self.updateButtonClick)
		deleteButton = Button(self.editPopup, text = "Delete Task", command=self.deleteButtonClick)
		completeButton = Button(self.editPopup, text = "Completed!", width=10, height=2, command=self.completeButtonClick)
		
		checkButton = Checkbutton(self.editPopup, text = " Important Task? ", command=self.reverseOutline, variable = self.isFlagged)

		if self.isFlagged:
			checkButton.select()
		else:
			checkButton.deselect()
		
		
		name.grid(row=0, column=0, pady=3)
		self.nameEntry.grid(row=0, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		description.grid(row=1, column=0, pady=3)
		self.descriptionEntry.grid(row=1, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		hoursCompleted.grid(row=2, column=0, pady=3)
		self.hoursCompletedEntry.grid(row=2, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		hoursTotal.grid(row=3, column=0, pady=3)
		self.hoursTotalEntry.grid(row=3, column=1, pady=3, padx = 5, sticky=W, columnspan=2)
		
		dueDate.grid(row=4, column=0, pady=3)
		self.dueDateEntry.grid(row=4, column=1, pady=3, padx = 5, sticky = W, columnspan=2)
		
		updateButton.grid(row=6, column = 0, pady=15, columnspan = 2)
		deleteButton.grid(row=6, column = 1, padx = 50, sticky = W, columnspan=2)
		completeButton.grid(row=2, column = 2, rowspan = 2, sticky = W)
		checkButton.grid(row=4, column=2, sticky=E, pady=5)
		
	def validation(self):
		description = self.descriptionEntry.get(1.0, END)
		hoursCompleted = self.hoursCompletedEntry.get()
		hoursTotal = self.hoursTotalEntry.get()
		self.dueDate = self.parseDateTime(self.dueDateEntry.get())

		try:
			int(hoursCompleted)
		except:
			hoursCompleted = "0"
		try:
			int(hoursTotal)
		except:
			hoursTotal = "1"

		self.description = description if len(description) > 0 else ""
		self.hoursCompleted = int(hoursCompleted if (len(hoursCompleted) > 0) else 0 )
		self.hoursTotal = int(hoursTotal if (len(hoursTotal) > 0) else 1)
		if isinstance(self, ProjectTask):
			self.panel.projectDict[self] = self.name


if __name__=="__main__":
	task = ProjectTask()











